/*   Copyright (C) 2008  Jeroen v. Schagen & Youri Lima
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections;

using Engine.Math;

namespace Engine
{
    /// <summary>
    ///     A composite can be thought of as a logical placeholder for data. 
    ///     
    ///     These objects contain a certain data unit and perhaps references 
    ///     to other nodes, which in turn contain data and perhaps references 
    ///     to yet more nodes.
    /// 
    ///     By forming chains of interlinked objects, very large and complex 
    ///     data structures can be formed.
    /// </summary>
    public abstract class Composite
    {
        protected Composite parent = null;
        protected ArrayList children = new ArrayList();

        # region Function

        /// <summary>
        ///     Calculate the hierarchical depth of this component,
        ///     in the related node structure.
        /// </summary>
        public int GetHierarchicalDepth()
        {
            Composite current = this;

            int depth = 0;
            while (! current.IsRoot())
            {
                current = current.GetParent();
                depth++;
            }

            return depth;
        }

        /// <summary>
        ///     Components at the bottom level of a tree hierarchy are called leafs. 
        ///     Since they are at bottom level, they do not have any children.
        /// </summary>
        public bool IsLeaf()
        {
            return children.Count == 0;
        }

        /// <summary>
        ///     The highest components in a tree hierarchy is called the root. 
        ///     Being the top component, it will not have parents.
        /// </summary>
        public bool IsRoot()
        {
            return parent == null;
        }

        # endregion


        # region Accessor

        /// <summary>
        ///     Retrieve the parent component of this component object.
        ///     If no parent can be found a null value will be returned.
        /// </summary>
        public Composite GetParent()
        {
            return parent;
        }

        /// <summary>
        ///     Change the components parent in the given argument,
        ///     this change will also influence the child property
        ///     of the old and new parent object.
        /// </summary>
        public void SetParent(Composite parent)
        {
            if (parent != null)
                parent.RemoveChild(this);

            // Store information
            this.parent = parent;

            if (parent != null)
                parent.AddChild(this);
        }

        /// <summary>
        ///     Retrieve the children collection as a component array.
        ///     If no children can be found an empty array will be returned.
        /// </summary>
        public Composite[] GetChildren()
        {
            return (Composite[]) children.ToArray();
        }

        /// <summary>
        ///     Attach a child to this component, this change will automaticly 
        ///     update the child's parent value in this component.
        /// </summary>
        public void AddChild(Composite child)
        {
            if (! ContainsChild(child))
            {
                children.Add(child);
            }
        }

        /// <summary>
        ///     Dettach a child from this component, this change will automaticly 
        ///     update the child's parent value in this component.
        /// </summary>
        public void RemoveChild(Composite child)
        {
            if (ContainsChild(child))
            {
                children.Remove(child);
            }
        }

        /// <summary>
        ///     Verify wether the given child argument is a child of this component.
        ///     If this happens to be true a true will be returned and visa versa.
        /// </summary>
        public bool ContainsChild(Composite child)
        {
            return children.Contains(child);
        }

        # endregion

        public override string ToString()
        {
            return base.ToString();
        }
    }
}